package ulmermark.demo.concurrency.core;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.joda.time.DateTime;

import ulmermark.demo.concurrency.core.inbox.InboxFactory;


public class TimerResource extends AbstractResource implements Resource<TimerResourceConfigParam>{

	private static final Logger LOGGER = Logger.getLogger( TimerResource.class);
	
	private final ScheduledExecutorService scheduler =
		     Executors.newScheduledThreadPool(5);
	
	private final ConcurrentHashMap<TimerKey, Timer> timers = new ConcurrentHashMap<TimerKey, Timer>();

	@SuppressWarnings("unchecked")
	public TimerResource(String name, final InboxFactory inboxFactory) {
		super(name, inboxFactory);
	
	}

	public void subscribeToTargets() {
	

	}

	@Override
	public void onAppInit() {
	

	}


	@Override
	public void start() {
	}

	public void schedule(String timerId, final Target<?> target, long delay,TimeUnit unit){
		final TimerKey key = new TimerKey( timerId);
		final Timer timer = new Timer(key,target,delay,unit);
		if ( timers.putIfAbsent(key, timer) != null) return; //timer/key already exists
		LOGGER.info("Scheduled " + key);
	}
	
	public <T extends Object> void  scheduleAtFixedRate(String timerId, final Target<T> target,long delay,final TimeUnit unit){
		final TimerKey key = new TimerKey( timerId);
		final Timer timer = new Timer(key,target,delay,unit);
		if ( timers.putIfAbsent(key, timer) != null) return; //timer/key already exists
		LOGGER.info("Scheduled " + key);
		
		ScheduledFuture<?> timerHandler = scheduler.scheduleAtFixedRate(new Runnable(){
			public void run(){
				LOGGER.info("Timer fired " + key);
				target.deliver((T)currentDateTime());
			}
		}, 0, delay, unit);
		
	}
	
	public DateTime currentDateTime(){
		return new DateTime();
	}
	
	/**
	 *
	 */
	private class TimerKey{
		private final String id;

		public TimerKey(String id) {
			this.id = id;
		}

		@Override
		public String toString(){
			return this.id;
		}
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + getOuterType().hashCode();
			result = prime * result + ((id == null) ? 0 : id.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			TimerKey other = (TimerKey) obj;
			if (!getOuterType().equals(other.getOuterType()))
				return false;
			if (id == null) {
				if (other.id != null)
					return false;
			} else if (!id.equals(other.id))
				return false;
			return true;
		}

		private TimerResource getOuterType() {
			return TimerResource.this;
		}


	}
	
	/**
	 *
	 */
	private class Timer{
		private TimerKey key;
		private Target<?> target;
		private long delay;
		private TimeUnit unit;
		
		public Timer(final TimerKey key, final Target<?> target, long delay, final TimeUnit unit) {
			this.key = key;
			this.target = target;
			this.delay = delay;
			this.unit = unit;
		}
		
		@Override
		public String toString(){
			return this.key.toString();
		}
	}

	@Override
	public void configure(final TimerResourceConfigParam configParam) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public TimerResourceConfigParam getConfig() {
		// TODO Auto-generated method stub
		return null;
	}

}
